<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// | 该文件的开源协议以所在项目的LICENSE文件为准，请遵守开源协议要求
// +----------------------------------------------------------------------
// | 通用方法处理
// +----------------------------------------------------------------------
namespace app\cms\http\web;

use Inphp\Core\Context;
use Inphp\Core\Middlewares\SmartyView;
use Inphp\Core\Modules;
use Inphp\Core\Services\Http\Response;
use Inphp\Core\Util\File;
use Inphp\Core\Util\Str;
use SmartyException;

abstract class controller
{
    /**
     * 初始化
     * @throws SmartyException
     */
    public function __construct()
    {
        $this->beforeExecute();
    }

    /**
     * 执行前拦截，并强制视图文件夹不存在
     * @throws SmartyException
     */
    public function beforeExecute()
    {
        $response = getHttpResponse();
        $status = $response->getRouterStatus();
        //加入一些默认数据
        $site = self::getRequestSite();
        $cms = Modules::getModule("cms");
        $template = $site["template"] ?? "default";
        $template = !empty($template) ? Str::trim($template) : "default";
        $templateDir = $cms->root."/template/{$template}";
        if (!is_dir($templateDir)) {
            showErrorPage("模板文件夹:{$template}，该文件夹不存在，无法进一步处理");
            return;
        }
        //存到当前
        Context::set("CMS_SITE", $site);
        //根据控制器，处理不同的模板类型
        $controller = is_string($status->controller[0]) ? $status->controller[0] : $status->controller[0]::class;
        //类名前缀
        $prefix = join("\\", ["cms", "http", "web"]);
        //可用控制器列表
        $files = File::getFiles($cms->root."/http/web", "php");
        foreach ($files as $file) {
            $filename = substr($file["filename"], 0, -4);
            if ($filename != "controller") {
                if (stripos($controller, $prefix."\\".$filename) > 0) {
                    Context::set("CMS_PAGE", $filename === "index" ? "home" : $filename);
                }
            }
        }
        //让默认的模板输出流程不进行处理
        $response->getRouterStatus()->view = null;
        $response->getRouterStatus()->viewDir = null;
    }

    /**
     * 响应前拦截，进行模板输出
     * @throws SmartyException
     */
    public function beforeEnd()
    {
        $response = getHttpResponse();
        if ($response instanceof Response) {
            //页面类型
            $page = Context::get("CMS_PAGE") ?? null;
            //站点
            $site = $this->getRequestSite();
            $cms = Modules::getModule("cms");
            $template = $site["template"] ?? "default";
            $template = !empty($template) ? Str::trim($template) : "default";
            $templateDir = $cms->root."/template/{$template}";
            $tplConfig = is_file($templateDir."/config.json") ? file_get_contents($templateDir."/config.json") : "";
            $tplConfig = !empty($tplConfig) ? (@json_decode($tplConfig, true) ?? []): [];
            $pages = $tplConfig["pages"] ?? [];
            $tpl = Context::get("CMS_".strtoupper($page)."_TPL");
            $tpl = !empty($tpl) ? $tpl : (!empty($pages[$page] && !empty($pages[$page][0]["file"])) ? $pages[$page][0]["file"] : $page);
            $tpl = !empty($tpl) ? Str::trim($tpl) : $page;
            $tpl = strrchr($tpl, ".") === ".html" ? $tpl : ($tpl.".html");
            //如果模板为空
            if (!is_file($templateDir."/".$tpl)) {
                if (is_file($templateDir."/error.html")) {
                    $this->showError("模板文件: {$tpl}，该文件不存在，无法进一步处理");
                    $tpl = "error.html";
                } else {
                    showErrorPage("模板文件: {$tpl}，该文件不存在，无法进一步处理");
                    return;
                }
            }
            if (empty($site) || $site["state"] != 1) {
                if (is_file($templateDir."/error_disable.html") || is_file($templateDir."/error.html")) {
                    $this->showError("由于您当前访问的站点未开放，无法展示相关内容，请稍后再试！", "站点未开放");
                    $tpl = is_file($templateDir."/error_disable.html") ? "error_disable.html" : "error.html";
                } else {
                    showErrorPage("由于您当前访问的站点未开放，无法展示相关内容，请稍后再试！", "站点未开放");
                    return;
                }
            }
            //增加模板可用的标签
            $this->setting();
            //初始化Smarty
            $smarty = SmartyView::init();
            $smarty->setTemplateDir($templateDir);
            $smarty->assign("site", $site);
            $smarty->assign("CMS_PAGE", $page);
            $smarty->assign("CMS_SITE", $site);
            //如果存在插件目录
            if (is_dir($cms->root."/tags/smarty")) {
                $files = File::getFiles($cms->root."/tags/smarty", "php");
                foreach ($files as $file) {
                    if (stripos($file["filename"], "smarty_") === 0) {
                        include_once $file["path"];
                    }
                }
            }
            $variables = [];
            //如果站点有配置文件，自动加载配置文件，并输出
            if (!empty($tplConfig["variables"])) {
                $variables = Modules::getModule("cms")->getConfig("var_{$template}");
                $variables = is_array($variables) ? $variables : [];
            }
            $smarty->assign("variables", $variables);
            $smarty->assign("TEMPLATE_VAR", $variables);
            //输出响应
            $response->withHtml($smarty->fetch($templateDir."/".$tpl));
        }
    }

    /**
     * 设置临时模板
     * @param string|null $tpl
     * @param string|null $page
     */
    public function setTPL(?string $tpl = null, ?string $page = null)
    {
        $page = $page ?? (Context::get("CMS_PAGE") ?? "home");
        Context::set("CMS_".strtoupper($page)."_TPL", $tpl);
    }

    /**
     * 展示404页面
     * @param string|null $page
     */
    public function show404(?string $page = null)
    {
        $page = $page ?? (Context::get("CMS_PAGE") ?? "home");
        $this->setTPL("error404.html", $page);
    }

    /**
     * 展示错误页面
     * @param string $message   错误详细说明
     * @param string $title     错误标题
     * @param string $code      错误码
     * @param string|null $page 当前页面类型
     */
    public function showError(string $message, string $title = "发生错误", string $code = "404", ?string $page = null)
    {
        viewAssign("error", [
            "title"     => $title,
            "message"   => $message,
            "code"      => $code
        ]);
        $page = $page ?? (Context::get("CMS_PAGE") ?? "home");
        Context::set("CMS_".strtoupper($page)."_TPL", "error.html");
    }

    /**
     * 自动匹配域名取得站点数据
     * @return array|null
     */
    public function getRequestSite(): ?array
    {
        //优先从上下文中获取
        if ($context = \Inphp\Core\Context::get("CMS_SITE")) {
            return $context;
        }
        //取站点ID
        $siteId = GET("siteId", \Inphp\Core\Services\Http\Session::get("CMS_siteId", \Inphp\Core\Services\Http\Cookie::get("CMS_siteId", 0)));
        $siteId = is_numeric($siteId) && $siteId > 0 ? ceil($siteId) : 0;
        $sites = \app\cms\model\SiteModel::getCache();
        $result = [];
        if ($siteId <= 0 && !empty($sites)) {
            //根据域名取
            $client = getClient();
            if (!empty($client->origin) && isset($sites[$client->origin])) {
                //存在与来源域名一致的站点
                $result = $sites[$client->origin];
            } elseif (isset($sites[$client->host])) {
                //存在与请求域名一致的站点
                $result =  $sites[$client->host];
            } else {
                //取默认站点
                foreach ($sites as $site) {
                    if ($site["default"] == 1) {
                        $result = $site;
                    }
                }
            }
        }
        $result = !empty($result) ? $result : (!empty($sites) ? reset($sites) : null);
        if (!empty($result)) {
            $result["logo"] = attachmentUrl($result["logo"]);
            \Inphp\Core\Context::set("CMS_SITE", $result);
            return $result;
        }
        return null;
    }

    /**
     * 其它设置
     */
    private function setting()
    {
        //自动获取标签库
        /*
        $cms = Modules::getModule("cms");
        $tagsFile = File::getFiles($cms->root."/tags", "php");
        foreach ($tagsFile as $file) {
            $tagName = substr($file["filename"], 0, -4);
            $class = "app\\cms\\tags\\{$tagName}";
            if (class_exists($class) && method_exists($class, "process")) {
                \Inphp\Core\Helper\SmartyPlugin::registerBlock($tagName, function (array $params, $content, \Smarty_Internal_Template $template, &$repeat) use($class) {
                    return $class::process($params, $content, $template, $repeat);
                });
            }
        }
        */
        //资源标签
        \Inphp\Core\Helper\SmartyPlugin::registerFunction("template", function (array $params = []) {
            $url = $params["url"] ?? null;
            if (!empty($url)) {
                //取当前站点
                $site = $this->getRequestSite();
                $template = $site["template"] ?? "default";
                $template = !empty($template) ? Str::trim($template) : "default";
                $url = stripos($url, "/") === 0 ? substr($url, 1) : $url;
                return assetsUrl("template/{$template}/{$url}", "cms");
            }
            return "";
        });
    }
}